package me.magicall.test.reflect.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

class DaoImplProxy implements InvocationHandler {

	public Object invoke(final Object proxy, final Method method, final Object[] args) {
		final String methodName = method.getName();
		//这三个方法比较特殊,要处理一下
		if (methodName.equals("toString")) {
			return proxy.getClass().getSimpleName() + "@" + hashCode();//注:这个hashCode是自己的
		}
		if (methodName.equals("equals")) {
			return proxy == args[0];
		}
		if (methodName.equals("hashCode")) {
			return hashCode();
		}
		//从数据库查出一个结果集 TODO
		final ResultSet rs = Util.select(methodName.equals("getList") ? "getList" : String.valueOf(args[0]));

		//首先来看dao的方法的返回类型
		final Class<?> returnType = method.getReturnType();

		if (Iterable.class.isAssignableFrom(returnType)) {//批量查询,即要返回的是一个collection
			//下面这两行代码可以获得泛型方法返回值尖括号里面的具体类型!!!
			final ParameterizedType type = (ParameterizedType) method.getGenericReturnType();
			final Class<?> acualType = (Class<?>) type.getActualTypeArguments()[0];
			System.out.println("@@@@@@" + acualType);
			try {
				final List<Object> list = new ArrayList<Object>();
				while (rs.next()) {
					list.add(getSingleBean(proxy, rs, acualType));
				}
				return list;
			} catch (final SQLException e) {
				throw new RuntimeException(e);
			}
		} else if (returnType == int.class || returnType == long.class//
				|| returnType == Integer.class || returnType == Long.class) {//查询数字(select count).不过也有可能是查询单个字段,其类型为int或bigint
			return 0;//TODO
		} else {//查询单个
			try {
				return rs.next() ? getSingleBean(proxy, rs, returnType) : null;
			} catch (final SQLException e) {
				throw new RuntimeException(e);
			}
		}
	}

	private static final String[][] EMPTY_PRIMARY_KEYS = {};

	/**
	 * 这个数组的外一维是所有uniq key,内一维是一个uniq key的字段组合.
	 * 
	 * @param daoInterface
	 * @return
	 */
	private String[][] primaryKeys(final Class<?> daoInterface) {
		final PrimaryKey annotation = daoInterface.getAnnotation(PrimaryKey.class);
		if (annotation == null) {
			return EMPTY_PRIMARY_KEYS;
		}
		final String[] pks = annotation.value();
		if (pks == null || pks.length == 0) {
			return EMPTY_PRIMARY_KEYS;
		}
		final String[][] rt = new String[pks.length][];
		for (int i = 0; i < pks.length; i++) {
			final String pk = pks[i];
			//注:注解上的方法不支持用二维数组做为返回类型!因此我们只好自己split
			final String[] comboPks = pk.split(",");
			for (int j = 0; j < comboPks.length; j++) {
				comboPks[j] = comboPks[j].trim();
			}
			rt[i] = comboPks;
		}
		return rt;
	}

	private Object getSingleBean(final Object proxy, final ResultSet rs, final Class<?> returnElementType) {
		final Class<?> clazz = proxy.getClass();
		final Class<?> daoInterface = clazz.getInterfaces()[0];//注:dao那个接口必须是implements后的第一个.

		//下面要获取dao接口上的两个注解的值
		final DBColumns dbColumnsAnnotation = daoInterface.getAnnotation(DBColumns.class);
		final String[] dbColumns = dbColumnsAnnotation.value();

		final DBFieldRef dbFieldRefAnnotation = daoInterface.getAnnotation(DBFieldRef.class);
		final String[] dbFieldRefs;
		if (dbFieldRefAnnotation == null) {
			dbFieldRefs = dbColumns;
		} else {
			final String[] ss = dbFieldRefAnnotation.value();
			if (ss == null || ss.length == 0) {
				dbFieldRefs = dbColumns;
			} else {
				if (ss.length != dbColumns.length) {
					throw new IllegalArgumentException("db columns count(" + dbColumns.length + ") and fields count(" + ss.length + ")");
				}
				dbFieldRefs = ss;
			}
		}

		final BeanImplProxy h = new BeanImplProxy(primaryKeys(daoInterface));
		for (int i = 0; i < dbColumns.length; i++) {
			final String fieldName = dbFieldRefs[i].trim();
			try {
				final Method getter = returnElementType.getMethod(Util.fieldNameToGetterName(fieldName));
				final Class<?> fieldType = getter.getReturnType();

				final String columnName = dbColumns[i].trim();
				final String columnValue = rs.getString(columnName);

				if (columnValue == null) {//在db中此字段的值为db的null
					if (fieldType.isPrimitive()) {//FIXME:似乎java推荐用0来代替db的null返回回去
						throw new IllegalArgumentException("a field value in db is null:" + fieldName);
					}
				} else {
					Object value = null;
					//按getter的返回值来解析值
					if (fieldType == int.class) {
						value = Integer.parseInt(columnValue);
					} else if (fieldType == long.class) {
						value = Long.parseLong(columnValue);
					} else if (fieldType == String.class) {
						value = columnValue;
					}//...TODO
					h.setValue(fieldName, value);
				}
			} catch (final NoSuchMethodException e) {
				//没事.有个字段在db有,在bean里没有(相应的getter),可能bean并不需要这个字段
			} catch (final SQLException e) {
				throw new RuntimeException(e);
			} catch (final SecurityException e) {
				e.printStackTrace();
				throw new IllegalArgumentException("check the bean interface,getters' modifier must be 'public'");
			}
		}
		return Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { User.class }, h);
	}
}